home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 016a / gofer221.zip / MAIN.C < prev    next >
C/C++ Source or Header  |  1991-11-20  |  30KB  |  1,001 lines

  1. /* --------------------------------------------------------------------------
  2.  * main.c:    Copyright (c) Mark P Jones 1991.   All rights reserved.
  3.  *        See goferite.h for details and conditions of use etc...
  4.  *        Gofer version 2.21 November 1991
  5.  *
  6.  *        Last updated 12/11/91 mpj
  7.  *
  8.  * Command interpreter
  9.  * ------------------------------------------------------------------------*/
  10.  
  11. #include "prelude.h"
  12. #include "storage.h"
  13. #include "command.h"
  14. #include "connect.h"
  15. #include "errors.h"
  16. #include <setjmp.h>
  17. #include <ctype.h>
  18.  
  19. #if TURBOC
  20. #include <sys\stat.h>
  21. #include <time.h>
  22. #endif
  23.  
  24. #if UNIX
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #endif
  28.  
  29. /* --------------------------------------------------------------------------
  30.  * Local function prototypes:
  31.  * ------------------------------------------------------------------------*/
  32.  
  33. static Void   local initialise          Args((Int,String []));
  34. static Void   local interpreter       Args((Int,String []));
  35.  
  36. static Void   local changeDir          Args((Void));
  37.  
  38. static Void   local set              Args((Void));
  39. static Void   local toggleSet          Args((Char,Bool));
  40. static Void   local togglesIn          Args((Bool));
  41. static Void   local optionInfo          Args((Void));
  42. static Void   local processOption     Args((String));
  43. static Int    local argToInt          Args((String *));
  44.  
  45. static Void   local load          Args((Void));
  46. static Void   local project           Args((Void));
  47. static Void   local loadProject       Args((String));
  48. static Void   local clearProject      Args((Void));
  49. static Void   local addScriptName     Args((String));
  50. static Void   local readScripts       Args((Int));
  51. static Void   local addScript          Args((String,Long));
  52. static Void   local forgetScriptsFrom Args((Module));
  53.  
  54. static Void   local editor          Args((Void));
  55. static Void   local find          Args((Void));
  56. static Void   local runEditor         Args((Void));
  57. static Void   local setLastEdit       Args((String,Int));
  58.  
  59. static Void   local evaluator          Args((Void));
  60. static Void   local stopAnyPrinting   Args((Void));
  61.  
  62. static Void   local showtype          Args((Void));
  63.  
  64. static Void   local listNames          Args((Void));
  65.  
  66. static Void   local help          Args((Void));
  67. static Void   local guidance          Args((Void));
  68. static Void   local forHelp          Args((Void));
  69.  
  70. static Void   local failed          Args((Void));
  71.  
  72. static String local strCopy          Args((String));
  73. static Int    local substr          Args((String,String));
  74.  
  75. /* --------------------------------------------------------------------------
  76.  * Local data areas:
  77.  * ------------------------------------------------------------------------*/
  78.  
  79. static String scriptName[NUM_MODULES];    /* Script file names           */
  80. static time_t lastChange[NUM_MODULES];    /* Time of last change to file       */
  81.  
  82. static Int    numScripts;        /* Number of scripts loaded       */
  83. static Int    namesUpto;        /* Number of script names set       */
  84.  
  85. static String currProject = 0;        /* Name of current project file       */
  86. static Bool   projectLoaded = FALSE;    /* TRUE => project file loaded       */
  87.  
  88. static String scriptFile;        /* Name of current script (if any) */
  89. static String lastEdit    = 0;        /* Name of file to edit (if any)   */
  90. static Int    lastLine    = 0;        /* Editor line number (if possible)*/
  91.  
  92. static Bool   printing    = FALSE;    /* TRUE => currently printing value*/
  93. static Bool   addType;            /* TRUE => print type with value   */
  94.  
  95. static String prompt;            /* Prompt string           */
  96. static Bool   showStats = TRUE;        /* TRUE => print stats after eval  */
  97.  
  98. /* --------------------------------------------------------------------------
  99.  * Gofer entry point:
  100.  * ------------------------------------------------------------------------*/
  101.  
  102. Void main Args((Int, String []));    /* now every func has a prototype  */
  103.  
  104. Void main(argc,argv)
  105. int  argc;
  106. char *argv[]; {
  107.     CStackBase = &argc;                 /* Save stack base for use in gc   */
  108.  
  109.     /* The startup banner now includes my name.  Gofer is provided free of */
  110.     /* charge.  I ask however that you show your appreciation for the many */
  111.     /* hours of work involved by retaining my name in the banner.  Thanks! */
  112.  
  113.     printf("Gofer Version 2.21  Copyright (c) Mark P Jones 1991\n\n");
  114.     fflush(stdout);
  115.     interpreter(argc,argv);
  116.     printf("[Leaving Gofer]\n");
  117.     everybody(EXIT);
  118.     exit(0);
  119. }
  120.  
  121. /* --------------------------------------------------------------------------
  122.  * Initialisation, interpret command line args and read prelude:
  123.  * ------------------------------------------------------------------------*/
  124.  
  125. static Void local initialise(argc,argv)/* interpreter initialisation       */
  126. Int    argc;
  127. String argv[]; {
  128.     Module i;
  129.     String proj = 0;
  130.  
  131.     lastEdit      = 0;
  132.     scriptFile      = 0;
  133.     numScripts      = 0;
  134.     namesUpto      = 1;
  135.     scriptName[0] = strCopy(fromEnv("GOFER","prelude"));
  136.     prompt      = strCopy("?");
  137.  
  138.     for (i=1; i<argc; ++i)        /* process command line arguments  */
  139.     if (strcmp(argv[i],"+")==0 && i+1<argc)
  140.         if (proj) {
  141.         ERROR(0) "Muliple project filenames on command line"
  142.         EEND;
  143.         }
  144.         else
  145.         proj = argv[++i];
  146.     else
  147.         addScriptName(argv[i]);
  148.  
  149.     everybody(INSTALL);
  150.     if (proj) {
  151.     if (namesUpto>1)
  152.         fprintf(stderr,
  153.             "\nUsing project file, ignoring additional filenames\n");
  154.     loadProject(strCopy(proj));
  155.     }
  156.     readScripts(0);
  157. }
  158.  
  159. /* --------------------------------------------------------------------------
  160.  * main read-eval-print loop, with error trapping:
  161.  * ------------------------------------------------------------------------*/
  162.  
  163. static jmp_buf catch_error;           /* jump buffer for error trapping   */
  164.  
  165. static Void local interpreter(argc,argv)/* main interpreter loop       */
  166. Int    argc;
  167. String argv[]; {
  168.     Int errorNumber = setjmp(catch_error);
  169.  
  170.     breakOn(TRUE);               /* enable break trapping        */
  171.     if (numScripts==0) {           /* only succeeds on first time,       */
  172.     if (errorNumber)           /* before prelude has been loaded   */
  173.         internal("Unable to load prelude");
  174.     initialise(argc,argv);
  175.     forHelp();
  176.     }
  177.  
  178.     for (;;) {
  179.     dropModulesFrom(numScripts-1); /* remove partially loaded scripts  */
  180.     everybody(RESET);           /* not counting prelude as a module */
  181.     printf("%s ",prompt);           /* print prompt string           */
  182.     fflush(stdout);
  183.  
  184.     consoleInput();
  185.     switch (readCommand()) {
  186.         case EDIT    : editor();
  187.               break;
  188.         case FIND   : find();
  189.               break;
  190.         case LOAD    : clearProject();
  191.               forgetScriptsFrom(1);
  192.               load();
  193.               break;
  194.         case ALSO   : clearProject();
  195.               forgetScriptsFrom(numScripts);
  196.               load();
  197.               break;
  198.         case RELOAD : readScripts(1);
  199.               break;
  200.         case PROJECT: project();
  201.               break;
  202.         case EVAL    : evaluator();
  203.               break;
  204.         case TYPEOF : showtype();
  205.               break;
  206.         case NAMES  : listNames();
  207.               break;
  208.         case HELP    : help();
  209.               break;
  210.         case BADCMD : guidance();
  211.               break;
  212.         case SET    : set();
  213.               break;
  214.         case SYSTEM : shellEsc(readLine());
  215.               break;
  216.         case CHGDIR : changeDir();
  217.               break;
  218.         case QUIT    : return;
  219.         case NOCMD    : break;
  220.     }
  221.     }
  222. }
  223.  
  224. static Void local changeDir() {        /* change directory           */
  225.     extern int chdir Args((String));
  226.     String s = readFilename();
  227.     if (s && chdir(s)) {
  228.     ERROR(0) "Unable to change to directory \"%s\"", s
  229.     EEND;
  230.     }
  231. }
  232.  
  233. Void errHead(l)                /* print start of error message       */
  234. Int l; {
  235.     failed();                   /* failed to reach target ...       */
  236.     stopAnyPrinting();
  237.     fprintf(errorStream,"ERROR");
  238.  
  239.     if (scriptFile) {
  240.     fprintf(errorStream," \"%s\"", scriptFile);
  241.     setLastEdit(scriptFile,l);
  242.     if (l) fprintf(errorStream," (line %d)",l);
  243.     scriptFile = 0;
  244.     }
  245.     fprintf(errorStream,": ");
  246.     fflush(errorStream);
  247. }
  248.  
  249. Void errFail() {               /* terminate error message and       */
  250.     putc('\n',errorStream);           /* produce exception to return to   */
  251.     fflush(errorStream);           /* main command loop           */
  252.     longjmp(catch_error,1);
  253. }
  254.  
  255. Void errAbort() {            /* altern. form of error handling  */
  256.     failed();                /* used when suitable error message*/
  257.     stopAnyPrinting();            /* has already been printed       */
  258.     errFail();
  259. }
  260.  
  261. Void internal(msg)               /* handle internal error        */
  262. String msg; {
  263.     fflush(stdout);
  264.     printf("\nINTERNAL ERROR: %s\n",msg);
  265.     everybody(EXIT);
  266.     exit(1);
  267. }
  268.  
  269. Int breakHandler() {               /* respond to break interrupt       */
  270.     breakOn(TRUE);
  271.     printf("{Interrupted!}\n");
  272.     everybody(BREAK);
  273.     failed();
  274.     stopAnyPrinting();
  275.     fflush(stdout);
  276.     longjmp(catch_error,1);
  277.     return(0); /*NOTREACHED*/
  278. }
  279.  
  280. /* --------------------------------------------------------------------------
  281.  * Setting of command line options:
  282.  * ------------------------------------------------------------------------*/
  283.  
  284. static Void local set() {        /* change command line options from*/
  285.     String s;                /* Gofer command line           */
  286.  
  287.     if (s=readFilename()) {
  288.     do {
  289.         if (s[0]=='+' || s[0]=='-')
  290.         processOption(s);
  291.         else {
  292.         ERROR(0) "Option string must begin with `+' or `-'"
  293.         EEND;
  294.         }
  295.     } while (s=readFilename());
  296.     }
  297.     else
  298.     optionInfo();
  299. }
  300.  
  301. static struct {                /* List of command line toggles       */
  302.     char   c;
  303.     String description;
  304.     Bool   *flag;
  305. } toggle[] = {
  306.     {'s', "Print no. reductions/cells after eval", &showStats},
  307.     {'t', "Print type after evaluation",       &addType},
  308.     {'d', "Show dictionary values in output exprs",&showDicts},
  309.     {'f', "Terminate evaluation on first error",   &failOnError},
  310.     {'g', "Print no. cells recovered after gc",       &gcMessages},
  311.     {'c', "Test conformality for pattern bindings",&useConformality},
  312.     {'l', "Treat input files as literate scripts", &literateScripts},
  313.     {'e', "Warn about errors in literate scripts", &literateErrors},
  314.     {'i', "Apply fromInteger to integer literals", &coerceNumLiterals},
  315.     {'o', "Optimise use of (&&) and (||)",       &andorOptimise},
  316.     {'u', "Catch ambiguously typed top-level vars",&catchAmbigs},
  317.     {'a', "Use any evidence, not nec. best",       &anyEvidence},
  318.     {'E', "Fail silently if evidence not found",   &silentEvFail},
  319.     {0,   0,                       0}
  320. };
  321.  
  322. static Void local toggleSet(c,state)    /* Set command line toggle       */
  323. Char c;
  324. Bool state; {
  325.     Int i;
  326.     for (i=0; toggle[i].c; ++i)
  327.     if (toggle[i].c == c) {
  328.         *toggle[i].flag = state;
  329.         return;
  330.     }
  331.     ERROR(0) "Unknown toggle `%c'", c
  332.     EEND;
  333. }
  334.  
  335. static Void local togglesIn(state)    /* Print current list of toggles in*/
  336. Bool state; {                /* given state               */
  337.     Int count = 0;
  338.     Int i;
  339.     for (i=0; toggle[i].c; ++i)
  340.     if (*toggle[i].flag == state) {
  341.         if (count==0)
  342.         putchar(state ? '+' : '-');
  343.         putchar(toggle[i].c);
  344.         count++;
  345.     }
  346.     if (count>0)
  347.     putchar(' ');
  348. }
  349.  
  350. static Void local optionInfo() {    /* Print information about command */
  351.     static String fmts = "%-5s%s\n";    /* line settings           */
  352.     static String fmtc = "%-5c%s\n";
  353.     Int    i;
  354.  
  355.     printf("Groups of options begin with +/- to turn options on/off resp.\n");
  356.     printf("\nTOGGLES:\n");
  357.     for (i=0; toggle[i].c; ++i)
  358.     printf(fmtc,toggle[i].c,toggle[i].description);
  359.  
  360.     printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n");
  361.     printf(fmts,"hnum","Set heap size (cannot be changed within Gofer)");
  362.     printf(fmts,"pstr","Set prompt string to str");
  363.     printf(fmts,"xnum","Set maximum depth for evidence search");
  364.  
  365.     printf("\nCurrent settings: ");
  366.     togglesIn(TRUE);
  367.     togglesIn(FALSE);
  368.     printf("-h%d -p%s -x%d\n",heapSize,prompt,maxEvidLevel);
  369. }
  370.  
  371. static Void local processOption(s)    /* process option string s       */
  372. String s; {
  373.     Bool state = (s[0]=='+' ? TRUE : FALSE);
  374.  
  375.     while (*++s)
  376.     switch (*s) {
  377.         case 'p' : if (s[1]) {
  378.                if (prompt) free(prompt);
  379.                prompt = strCopy(s+1);
  380.                }
  381.                return;
  382.  
  383.         case 'h' : if (heapBuilt()) {
  384.                ERROR(0) "Cannot change heap size"
  385.                EEND;
  386.                }
  387.                heapSize = argToInt(&s);
  388.                if (heapSize<MINIMUMHEAP)
  389.                heapSize = MINIMUMHEAP;
  390. #if MAXIMUMHEAP > 0
  391.                else if (heapSize>MAXIMUMHEAP)
  392.                heapSize = MAXIMUMHEAP;
  393. #endif
  394.                break;
  395.  
  396.         case 'x' : maxEvidLevel = argToInt(&s);
  397.                break;
  398.  
  399.         default  : toggleSet(*s,state);
  400.                break;
  401.     }
  402. }
  403.  
  404. static Int local argToInt(sp)        /* read integer from argument str  */
  405. String *sp; {
  406.     Int num = 0;
  407.     while (isascii((*sp)[1]) && isdigit((*sp)[1])) {
  408.     num = 10*num + (*(++*sp) - '0');
  409.     }
  410.     return num;
  411. }
  412.  
  413. /* --------------------------------------------------------------------------
  414.  * Loading and removal of script files:
  415.  * ------------------------------------------------------------------------*/
  416.  
  417. static Void local load() {           /* read filenames from command line */
  418.     String s;                   /* and add to list of files waiting */
  419.                        /* to be read               */
  420.     while (s=readFilename())
  421.     addScriptName(s);
  422.     readScripts(1);
  423. }
  424.  
  425. static Void local project() {           /* read list of file names from     */
  426.     String s;                   /* project file               */
  427.  
  428.     if ((s=readFilename()) || currProject) {
  429.     if (!s)
  430.         s = strCopy(currProject);
  431.     else if (readFilename()) {
  432.         ERROR(0) "Too many project files"
  433.         EEND;
  434.     }
  435.     else
  436.         s = strCopy(s);
  437.     }
  438.     else {
  439.     ERROR(0) "No project filename specified"
  440.     EEND;
  441.     }
  442.     loadProject(s);
  443.     readScripts(1);
  444. }
  445.  
  446. static Void local loadProject(s)    /* Load project file          */
  447. String s; {
  448.     clearProject();
  449.     currProject = s;
  450.     projInput(currProject);
  451.     scriptFile = currProject;
  452.     forgetScriptsFrom(1);
  453.     while (s=readFilename())
  454.     addScriptName(s);
  455.     if (namesUpto<=1) {
  456.     ERROR(0) "Empty project file"
  457.     EEND;
  458.     }
  459.     scriptFile    = 0;
  460.     projectLoaded = TRUE;
  461. }
  462.  
  463. static Void local clearProject() {     /* clear name for current project   */
  464.     if (currProject)
  465.     free(currProject);
  466.     currProject   = 0;
  467.     projectLoaded = FALSE;
  468. }
  469.  
  470. static Void local addScriptName(s)     /* add script name to list of files */
  471. String s; {                   /* to be read in ...           */
  472.     if (s[0]=='-' || s[0]=='+')
  473.     processOption(s);
  474.     else if (namesUpto>=NUM_MODULES) {
  475.     ERROR(0) "Too many script files (maximum of %d allowed)",
  476.          NUM_MODULES
  477.     EEND;
  478.     }
  479.     else
  480.     scriptName[namesUpto++] = strCopy(s);
  481. }
  482.  
  483. static Void local readScripts(first)   /* reread current list of scripts,  */
  484. Int first; {                   /* loading everything after and       */
  485.     static struct stat scbuf;           /* including the first script which */
  486.     Module i;                   /* has been either changed of added */
  487.  
  488.     for (i=first; i<namesUpto; ++i) {
  489.     stat(scriptName[i],&scbuf);
  490.  
  491.     if (i<numScripts && scbuf.st_mtime!=lastChange[i]) {
  492.         dropModulesFrom(i-1);    /* previously loaded file changed ?*/
  493.         numScripts = i;
  494.     }
  495.  
  496.     if (i>=numScripts) {        /* new script file to be read ?       */
  497.         lastChange[i] = scbuf.st_mtime;
  498.         if (i>0)            /* no new module for prelude       */
  499.         startNewModule();
  500.         addScript(scriptName[i],((Long)scbuf.st_size));
  501.         numScripts++;
  502.     }
  503.     }
  504.  
  505.     printf("\nGofer session for:");
  506.     if (projectLoaded)
  507.     printf(" (project: %s)",currProject);
  508.     for (i=0; i<numScripts; ++i)
  509.     printf("\n%s",scriptName[i]);
  510.     putchar('\n');
  511.     if (numScripts<=1)
  512.     lastEdit = 0;
  513. }
  514.  
  515. static Void local addScript(fname,len) /* read single script file       */
  516. String fname;                   /* name of script file           */
  517. Long   len; {                   /* length of script file        */
  518.     scriptFile = fname;
  519.  
  520.     printf("Reading script file \"%s\":\n",fname);
  521.     setLastEdit(fname,0);
  522.     parseScript(fname,len);           /* process script file           */
  523.     checkDefns();
  524.     typeCheckDefns();
  525.     compileDefns();
  526.     scriptFile = 0;
  527. }
  528.  
  529. static Void local forgetScriptsFrom(scno)/* remove scripts from system       */
  530. Module scno; {
  531.     Module i;
  532.     for (i=scno; i<namesUpto; ++i)
  533.     if (scriptName[i])
  534.         free(scriptName[i]);
  535.     dropModulesFrom(scno-1);         /* don't count prelude as module  */
  536.     namesUpto = scno;
  537.     if (numScripts>0)
  538.     numScripts = scno;
  539. }
  540.  
  541. /* --------------------------------------------------------------------------
  542.  * Access to external editor:
  543.  * ------------------------------------------------------------------------*/
  544.  
  545. static Void local editor() {        /* interpreter-editor interface       */
  546.     String newFile  = readFilename();
  547.     if (newFile) {
  548.     setLastEdit(newFile,0);
  549.     if (readFilename()) {
  550.         ERROR(0) "Multiple filenames not permitted"
  551.         EEND;
  552.     }
  553.     }
  554.     runEditor();
  555.     readScripts(1);            /* try to reload scripts after edit*/
  556. }
  557.  
  558. static Void local find() {        /* edit file containing definition */
  559.     String nm = readFilename();        /* of specified name           */
  560.     if (!nm) {
  561.     ERROR(0) "No name specified"
  562.     EEND;
  563.     }
  564.     else if (readFilename()) {
  565.     ERROR(0) "Multiple names not permitted"
  566.     EEND;
  567.     }
  568.     else {
  569.     Name n;
  570.     startNewModule();
  571.     if (isNull(n = findName(findText(nm)))) {
  572.         ERROR(0) "No current definition for name \"%s\"", nm
  573.         EEND;
  574.     }
  575.     setLastEdit(scriptName[moduleThisName(n)],name(n).line);
  576.     runEditor();
  577.     readScripts(1);
  578.     }
  579. }
  580.  
  581. static Void local runEditor() {        /* run editor on file lastEdit at  */
  582.     static char editorCmd[100];        /* line editLine           */
  583.     String editor   = fromEnv("EDITOR",DEF_EDITOR);
  584.     String editline = fromEnv("EDITLINE",DEF_EDITLINE);
  585.     Int    l,f;
  586.  
  587.     if (lastEdit && editline && lastLine
  588.                  && (l=substr("%d",editline))>=0
  589.                  && (f=substr("%s",editline))>=0)
  590.         if (l<f)
  591.         sprintf(editorCmd,editline,lastLine,lastEdit);
  592.     else
  593.         sprintf(editorCmd,editline,lastEdit,lastLine);
  594.     else if (editor)
  595.     if (lastEdit)
  596.         sprintf(editorCmd,"%s %s",editor,lastEdit);
  597.     else
  598.         sprintf(editorCmd,"%s",editor);
  599.     else {
  600.     ERROR(0) "No editor specified in environment variable EDITOR"
  601.     EEND;
  602.     }
  603.  
  604.     if (shellEsc(editorCmd)) {
  605.     ERROR(0) "Editor terminated abnormally"
  606.     EEND;
  607.     }
  608. }
  609.  
  610. static Void local setLastEdit(fname,line)/* keep name of last file to edit */
  611. String fname;
  612. Int    line; {
  613.     if (lastEdit)
  614.     free(lastEdit);
  615.     lastEdit = strCopy(fname);
  616.     lastLine = line;
  617. }
  618.  
  619. /* --------------------------------------------------------------------------
  620.  * Read and evaluate an expression:
  621.  * ------------------------------------------------------------------------*/
  622.  
  623. static Void local evaluator() {        /* evaluate expr and print value    */
  624.     Type type;
  625.  
  626.     scriptFile = 0;
  627.     startNewModule();               /* Enables recovery of storage       */
  628.                        /* allocated during evaluation       */
  629.     parseExp();
  630.     checkExp();
  631.     type = typeCheckExp();
  632.     if (whatIs(isPolyType(type) ? snd(type) : type)==QUAL) {
  633.     ERROR(0) "Unresolved overloading" ETHEN
  634.     ERRTEXT  "\n*** type        : "   ETHEN ERRTYPE(type);
  635.     ERRTEXT  "\n*** translation : "   ETHEN ERREXPR(inputExpr);
  636.     ERRTEXT  "\n"
  637.     EEND;
  638.     }
  639.     compileExp();
  640.     numCells      = 0;
  641.     numReductions = 0;
  642.     numberGcs     = 0;
  643.     printing      = TRUE;
  644.     if (typeMatches(type,typeString))
  645.     outputString(stdout,graphForExp(),TRUE);
  646.     else if (typeMatches(type,typeDialogue))
  647.     dialogue(graphForExp());
  648.     else {
  649.     outputString(stdout,ap(ap(ap(namePrint,
  650.                      mkInt(MIN_PREC)),
  651.                      graphForExp()),
  652.                      nameNil),TRUE);
  653.     if (addType) {
  654.         printf(" :: ");
  655.         printType(stdout,type);
  656.     }
  657.     }
  658.     stopAnyPrinting();
  659. }
  660.  
  661. static Void local stopAnyPrinting() {  /* terminate printing of expression,*/
  662.     if (printing) {               /* after successful termination or  */
  663.     printing = FALSE;           /* runtime error (e.g. interrupt)   */
  664.     putchar('\n');
  665.     if (showStats) {
  666. #define plural(v)   v, (v==1?"":"s")
  667.         printf("(%lu reduction%s, ",plural(numReductions));
  668.         printf("%lu cell%s",plural(numCells));
  669.         if (numberGcs>0)
  670.         printf(", %u garbage collection%s",plural(numberGcs));
  671.         printf(")\n");
  672. #undef plural
  673.     }
  674.     fflush(stdout);
  675.     }
  676. }
  677.  
  678. /* --------------------------------------------------------------------------
  679.  * Print type of input expression:
  680.  * ------------------------------------------------------------------------*/
  681.  
  682. static Void local showtype() {           /* print type of expression (if any)*/
  683.     Cell type;
  684.  
  685.     startNewModule();               /* Enables recovery of storage       */
  686.                        /* allocated during evaluation       */
  687.     parseExp();
  688.     checkExp();
  689.     type = typeCheckExp();
  690.     printExp(stdout,inputExpr);
  691.     printf(" :: ");
  692.     printType(stdout,type);
  693.     putchar('\n');
  694. }
  695.  
  696. /* --------------------------------------------------------------------------
  697.  * List all names currently in scope:
  698.  * ------------------------------------------------------------------------*/
  699.  
  700. static Void local listNames() {        /* list names matching optional pat*/
  701.     String pat   = readFilename();
  702.     List   names = NIL;
  703.     Int    width = getTerminalWidth() - 1;
  704.     Int    count = 0;
  705.     Int    termPos;
  706.  
  707.     if (pat)                /* First gather names to list       */
  708.     do
  709.         names = addNamesMatching(pat,names);
  710.     while (pat=readFilename());
  711.     else
  712.     names = addNamesMatching((String)0,names);
  713.  
  714.     if (isNull(names)) {        /* Then print them out           */
  715.     ERROR(0) "No names selected"
  716.     EEND;
  717.     }
  718.     for (termPos=0; nonNull(names); names=tl(names)) {
  719.     String s = textToStr(name(hd(names)).text);
  720.     Int    l = strlen(s);
  721.     if (termPos+1+l>width) {
  722.         putchar('\n');
  723.         termPos = 0;
  724.     }
  725.     else if (termPos>0) {
  726.         putchar(' ');
  727.         termPos++;
  728.     }
  729.     printf("%s",s);
  730.     termPos += l;
  731.     count++;
  732.     }
  733.     printf("\n(%d names listed)\n", count);
  734. }
  735.  
  736. /* --------------------------------------------------------------------------
  737.  * Print Menu of list of commands:
  738.  * ------------------------------------------------------------------------*/
  739.  
  740. static Void local help() {
  741.     printf("LIST OF COMMANDS:  Any command may be abbreviated to :c where\n");
  742.     printf("c is the first character in the full name.\n\n");
  743.     printf(":set <options>      set command line options\n");
  744.     printf(":set                help on command line options\n");
  745.     printf(":?                  display this list of commands\n");
  746.     printf("<expr>              evaluate expression\n");
  747.     printf(":type <expr>        print type of expression\n");
  748.     printf(":names [pat]        list names currently in scope\n");
  749.     printf(":load <filenames>   load scripts from specified files\n");
  750.     printf(":load               clear all files except prelude\n");
  751.     printf(":also <filenames>   read additional script files\n");
  752.     printf(":reload             repeat last load command\n");
  753.     printf(":project <filename> use project file\n");
  754.     printf(":edit <filename>    edit file\n");
  755.     printf(":edit               edit last file\n");
  756.     printf(":find <name>        edit file containing definition of name\n");
  757.     printf(":! command          shell escape\n");
  758.     printf(":cd dir             change directory\n");
  759.     printf(":quit               exit Gofer interpreter\n");
  760. }
  761.  
  762. Char cmdFirstChar = ':';
  763. struct cmd commands[] = {
  764.  {":?",       HELP},    {":type",   TYPEOF}, {":load",    LOAD},
  765.  {":also", ALSO},    {":reload", RELOAD}, {":project", PROJECT},
  766.  {":edit", EDIT},    {":find",   FIND},   {":names",   NAMES},
  767.  {":set",  SET},     {":quit",   QUIT},   {":cd",      CHGDIR},
  768.  {":!",    SYSTEM},  {"",     EVAL},
  769.  {0,0}
  770. };
  771.  
  772. static Void local guidance() {
  773.     printf("Command not recognised.  ");
  774.     forHelp();
  775. }
  776.  
  777. static Void local forHelp() {
  778.     printf("Type :? for help\n");
  779. }
  780.  
  781. /* --------------------------------------------------------------------------
  782.  * Display progress towards goal:
  783.  * ------------------------------------------------------------------------*/
  784.  
  785. static Target currTarget;
  786. static Int    currPos;
  787. static Int    maxPos;
  788. static Bool   aiming = FALSE;
  789.  
  790. Void setGoal(what, t)               /* Set goal for what to be t       */
  791. String what;
  792. Target t; {
  793.     currTarget = (t?t:1);
  794.     currPos    = strlen(what);
  795.     maxPos     = getTerminalWidth() - 1;
  796.     aiming     = TRUE;
  797.  
  798.     printf("%s",what);
  799.     fflush(stdout);
  800. }
  801.  
  802. Void soFar(t)                   /* Indicate progress towards goal   */
  803. Target t; {                   /* has now reached t           */
  804.     Int newPos = (Int)((maxPos * ((long)t))/currTarget);
  805.  
  806.     if (newPos>maxPos)
  807.     newPos = maxPos;
  808.  
  809.     if (newPos>currPos) {
  810.     do
  811.         putchar('.');
  812.     while (newPos>++currPos);
  813.     fflush(stdout);
  814.     }
  815. }
  816.  
  817. Void done() {                   /* Goal has now been achieved       */
  818.     while (maxPos>currPos++)
  819.     putchar('.');
  820.     putchar('\n');
  821.     fflush(stdout);
  822.     aiming = FALSE;
  823. }
  824.  
  825. static Void local failed() {           /* Goal cannot be reached due to    */
  826.     if (aiming) {               /* errors               */
  827.     aiming = FALSE;
  828.     putchar('\n');
  829.     fflush(stdout);
  830.     }
  831. }
  832.  
  833. /* --------------------------------------------------------------------------
  834.  * Send message to each component of system:
  835.  * ------------------------------------------------------------------------*/
  836.  
  837. Void everybody(what)        /* send command `what' to each component of*/
  838. Int what; {            /* system to respond as appropriate ...    */
  839.     machdep(what);        /* The order of calling each component is  */
  840.     storage(what);        /* important for the INSTALL command       */
  841.     input(what);
  842.     staticAnalysis(what);
  843.     typeChecker(what);
  844.     compiler(what);
  845.     machine(what);
  846.     builtIn(what);
  847. }
  848.  
  849. /* --------------------------------------------------------------------------
  850.  * Read value from environment variable:
  851.  * ------------------------------------------------------------------------*/
  852.  
  853. String fromEnv(var,def)        /* return value of:                */
  854. String var;            /*     environment variable named by var   */
  855. String def; {            /* or: default value given by def       */
  856.     extern char *getenv Args((char *));
  857.     String s = getenv(var);
  858.  
  859.     return (s ? s : def);
  860. }
  861.  
  862. /* --------------------------------------------------------------------------
  863.  * String manipulation routines:
  864.  * ------------------------------------------------------------------------*/
  865.  
  866. static String local strCopy(s)           /* make malloced copy of a string   */
  867. String s; {
  868.     char *t,*r;
  869.  
  870.     if ((t=(char *)malloc(strlen(s)+1))==0) {
  871.     ERROR(0) "String storage space exhausted"
  872.     EEND;
  873.     }
  874.     for (r=t; *r++ = *s++;)
  875.     ;
  876.     return t;
  877. }
  878.  
  879. static Int local substr(s1,s2)        /* find posn of substring s1 in s2 */
  880. String s1, s2; {            /* (naive implementation)       */
  881.     String t;
  882.  
  883.     for (t=s2; *t; t++) {
  884.     Int i = 0;
  885.         while (s1[i] && s1[i]==t[i])
  886.         i++;
  887.     if (s1[i]=='\0')
  888.         return t-s2;
  889.     }
  890.     return (-1);
  891. }
  892.  
  893. #define USE_REGEXP 0
  894. #if USE_REGEXP
  895. /* --------------------------------------------------------------------------
  896.  * String matching using regular expressions:
  897.  *
  898.  * Relies on the regexp.h header file provided by many UNIX systems.
  899.  * If you do not have this file for your your system/compiler you will
  900.  * have to set   #define USE_REGEXP 0   above and use the simple string
  901.  * matching routine below.
  902.  * ------------------------------------------------------------------------*/
  903.  
  904. #define  INIT        register char *sp = instring;
  905. #define  GETC()     (*sp++)
  906. #define  PEEKC()    (*sp)
  907. #define  UNGETC(c)  (--sp)
  908. #define  RETURN(c)  return c
  909. #define  ERROR(c)   regErr(c)
  910. #define  ESIZE      200
  911.  
  912. static Void local regErr  Args((int));    /* report error in regular expr       */
  913. static Void local regErr(errorcode)
  914. int errorcode; {
  915.     if (errorcode==50) {
  916.     ERROR(0) "Regular expression too complex"
  917.     EEND;
  918.     }
  919.     else {
  920.     ERROR(0) "Error in regular expression"
  921.     EEND;
  922.     }
  923. }
  924.  
  925. #include <regexp.h>
  926.  
  927. Bool stringMatch(pat,str)        /* match string against pattern       */
  928. String pat;
  929. String str; {
  930.     char expbuf[ESIZE];
  931.     compile(pat,expbuf,&expbuf[ESIZE],'\0');
  932.     return step(str,expbuf);
  933. }
  934. #else
  935. /* --------------------------------------------------------------------------
  936.  * A simple string matching routine
  937.  *     `*'    matches any sequence of zero or more characters
  938.  *     `?'    matches any single character exactly 
  939.  *     `@str' matches the string str exactly (ignoring any special chars)
  940.  *     `\c'   matches the character c only (ignoring special chars)
  941.  *     c      matches the character c only
  942.  * ------------------------------------------------------------------------*/
  943.  
  944. static Void local patternError Args((String));
  945. static Void local patternError(s)    /* report error in pattern       */
  946. String s; {
  947.     ERROR(0) "%s in pattern", s
  948.     EEND;
  949. }
  950.  
  951. Bool stringMatch(pat,str)        /* match string against pattern       */
  952. String pat;
  953. String str; {
  954.  
  955.     for (;;)
  956.     switch (*pat) {
  957.         case '\0' : return (*str=='\0');
  958.  
  959.         case '*'  : do {
  960.                 if (stringMatch(pat+1,str++))
  961.                 return TRUE;
  962.             } while (*str);
  963.             pat++;
  964.             break;
  965.  
  966.             case '?'  : if (*str++=='\0')
  967.                 return FALSE;
  968.             pat++;
  969.             break;
  970.  
  971.             case '['  : {   Bool found = FALSE;
  972.                 while (*++pat!='\0' && *pat!=']')
  973.                 if (!found && ( pat[0] == *str  ||
  974.                            (pat[1] == '-'   &&
  975.                         pat[2] != ']'   &&
  976.                         pat[2] != '\0'  &&
  977.                         pat[0] <= *str  &&
  978.                         pat[2] >= *str)))
  979.                                                
  980.                     found = TRUE;
  981.                 if (*pat != ']')
  982.                 patternError("missing `]'");
  983.                 if (!found)
  984.                 return FALSE;
  985.                 pat++;
  986.                 str++;
  987.             }
  988.                         break;
  989.  
  990.         case '\\' : if (*++pat == '\0')
  991.                 patternError("extra trailing `\\'");
  992.             /*fallthru!*/
  993.         default   : if (*pat++ != *str++)
  994.                 return FALSE;
  995.             break;
  996.     }
  997. }
  998. #endif
  999.  
  1000. /*-------------------------------------------------------------------------*/
  1001.